package com.leen.admin.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.leen.admin.constant.AdminConstant;
import com.leen.admin.dto.MenuDTO;
import com.leen.admin.entity.*;
import com.leen.admin.repository.AdminRepository;
import com.leen.admin.repository.MenuRepository;
import com.leen.admin.service.AdminService;
import com.leen.admin.service.MenuService;
import com.leen.admin.vo.menu.MenuMetaVo;
import com.leen.admin.vo.menu.MenuTreeVO;
import com.leen.admin.vo.menu.MenuVo;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 类说明
 *
 * @author admin
 * @date 2021-05-21
 */
@Service
@Log4j2
@Transactional(rollbackFor = Exception.class)
public class MenuServiceImpl extends CurdServiceImpl<Menu,Integer> implements MenuService {

    private MenuRepository menuRepository;

    @Autowired
    private AdminRepository adminRepository;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    public void setMenuRepository(MenuRepository menuRepository) {
        this.menuRepository = menuRepository;
        super.setCrudRepository(menuRepository);
    }


    @Override
    public List<MenuDTO> findMenuByAdminId(Integer adminId) {
        List<Menu> adminOwnMenu = getAdminOwnMenu(adminId);

        List<MenuDTO>  buildMenuList=new ArrayList<>();

        if(adminOwnMenu!=null && adminOwnMenu.size()>0){
            for(Menu menu : adminOwnMenu){

                if(menu.getParentId().equals(0)){
                    MenuDTO  menuDTO=new MenuDTO();
                    BeanUtils.copyProperties(menu,menuDTO);
                    buildMenuList.add(menuDTO);

                    //循环二级节点
                    recursion(adminOwnMenu,menuDTO);
                } 
            }
        }

        return buildMenuList;
    }



    /**
     * 构造前端项目的菜单样式数据
     *
     * @param menuDtos /
     * @return /
     */
    @Override
    public List<MenuVo> buildMenus(List<MenuDTO> menuDtos) {
        List<MenuVo> list = new LinkedList<>();
        menuDtos.forEach(menuDTO -> {
                    if (menuDTO != null) {
                        List<MenuDTO> menuDtoList = menuDTO.getChildren();
                        MenuVo menuVo = new MenuVo();
                        menuVo.setName(ObjectUtil.isNotEmpty(menuDTO.getComponentName()) ? menuDTO.getComponentName() : menuDTO.getMenuName());
                        // 一级目录需要加斜杠，不然会报警告
                        menuVo.setPath(menuDTO.getParentId().equals(0) ? "/" + menuDTO.getPath() : menuDTO.getPath());
                        menuVo.setHidden(menuDTO.getHidden());
                        // 如果不是外链
                        if (menuDTO.getFrame()==0) {
                            if (menuDTO.getParentId().equals(0) ) {
                                menuVo.setComponent(StrUtil.isEmpty(menuDTO.getComponent()) ? "Layout" : menuDTO.getComponent());
                            } else if (!StrUtil.isEmpty(menuDTO.getComponent())) {
                                menuVo.setComponent(menuDTO.getComponent());
                            }
                        }
                        menuVo.setMeta(new MenuMetaVo(menuDTO.getMenuName(), menuDTO.getIcon(), !menuDTO.getCache()));
                        if (menuDtoList != null && menuDtoList.size() != 0) {
                            menuVo.setAlwaysShow(true);
                            menuVo.setRedirect("noredirect");
                            menuVo.setChildren(buildMenus(menuDtoList));
                            // 处理是一级菜单并且没有子菜单的情况
                        } else if (menuDTO.getParentId() .equals(0)) {
                            MenuVo menuVo1 = new MenuVo();
                            menuVo1.setMeta(menuVo.getMeta());
                            // 非外链
                            if (menuDTO.getFrame()==0) {
                                menuVo1.setPath("index");
                                menuVo1.setName(menuVo.getName());
                                menuVo1.setComponent(menuVo.getComponent());
                            } else {
                                menuVo1.setPath(menuDTO.getPath());
                            }
                            menuVo.setName(null);
                            menuVo.setMeta(null);
                            menuVo.setComponent("Layout");
                            List<MenuVo> list1 = new ArrayList<>();
                            list1.add(menuVo1);
                            menuVo.setChildren(list1);
                        }
                        list.add(menuVo);
                    }
                }
        );
        return list;
    }



    private void recursion(List<Menu> adminOwnMenu , MenuDTO parent){
        List<MenuDTO> childList=new ArrayList<>();
        for(Menu menu : adminOwnMenu){
            if(!menu.getParentId().equals(0)  && menu.getParentId().equals(parent.getMenuId())){

                MenuDTO  child=new MenuDTO();
                BeanUtils.copyProperties(menu,child);
                childList.add(child);
            }
        }

        if(childList.size()>0){
            parent.setChildren(childList);
        }

    }

    /**
     * 根据id查询它拥有的菜单
     * @param adminId
     * @return
     */
    private List<Menu> getAdminOwnMenu(Integer adminId){

        List<Menu>  allMenu=new ArrayList<>();

        Admin dbAdmin=this.adminRepository.findById(adminId).get();
        List<AdminRole> adminRoleList = dbAdmin.getAdminRoleList();

        if(adminRoleList!=null && adminRoleList.size()>0){
            for (AdminRole ar:  adminRoleList) {
                Role role = ar.getRole();
                List<RoleMenu> roleMenuList = role.getRoleMenuList();
                if(roleMenuList!=null && roleMenuList.size()>0){
                    for(RoleMenu rm: roleMenuList){
                        Menu menu = rm.getMenu();
                        if(!allMenu.contains(menu))  {
                            allMenu.add(menu);
                        }
                    }
                }
            }
        }
        return allMenu;
    }




    /**
     * 根据所有菜单构造权限分配的菜单树（做缓存优化,所有菜单都是一模一样的,没有必要每一次查询）
     * @return
     */
    @Override
    public List<MenuTreeVO> buildMenuTree() {
        //组装的
        final List<MenuTreeVO>  buildTreeList=new ArrayList<>();

        //判断redis中是否有值，如果有，直接返回
        String redisValue=this.stringRedisTemplate.opsForValue().get(AdminConstant.MENU_TREE_REDIS_KEY);

        if(StringUtils.isNotBlank(redisValue)){
            List<MenuTreeVO>  list= JSONArray.parseArray(redisValue, MenuTreeVO.class);
            buildTreeList.addAll(list);

        }else{

            //所有菜单
            Iterable<Menu> allMenu = this.menuRepository.findAll();

            allMenu.forEach( m -> {
                //顶级节点
                if(m.getParentId()==null || m.getParentId().equals(0)){
                    MenuTreeVO root=new MenuTreeVO();
                    root.setMenuId( m.getMenuId());
                    root.setParentId(m.getParentId());
                    root.setMenuName(m.getMenuName());
                    //查询它的下一级
                    buildChildTree(allMenu, root);

                    buildTreeList.add(root);
                }
            });

            //放到redis中
            redisValue=JSONArray.toJSONString(buildTreeList);
            this.stringRedisTemplate.opsForValue().set(AdminConstant.MENU_TREE_REDIS_KEY, redisValue,AdminConstant.MENU_TREE_REDIS_KEY_EXPIRED_DAYS, TimeUnit.DAYS);
        }

        return buildTreeList;
    }


    private void buildChildTree( Iterable<Menu> allMenu  , MenuTreeVO root ){
        //组装的
        List<MenuTreeVO>  buildTreeList=new ArrayList<>();

        allMenu.forEach(m-> {

            if(m.getParentId()!=null && m.getParentId().equals( root.getMenuId())){
                MenuTreeVO child=new MenuTreeVO();
                child.setMenuId( m.getMenuId());
                child.setParentId(m.getParentId());
                child.setMenuName(m.getMenuName());

                // 再继续遍历下一级
                buildChildTree(allMenu, child);

                buildTreeList.add(child);
            }

        });



        //添加
        if(buildTreeList.size()>0){
            root.setChildren(buildTreeList);
        }
    }


    /**
     * 获取角色拥有菜单编号
     * @param roleId
     * @return
     */
    @Override
    public Set<Integer> searchOwnMenuIdByRoleId(int roleId) {
        Set<Integer>  setArr=new HashSet<>();

        List resultObj=this.menuRepository.OwnMenuIdByRoleId(roleId);
        if(resultObj!=null){

           for(Object item : resultObj){
               setArr.add( (int)item);
           }
        }

        return setArr;
    }


}

